package com.slofzx.nuoda.evaluation.project.builder;

import com.alibaba.fastjson.JSON;
import com.slofzx.nuoda.common.util.DataConvertUtil;
import com.slofzx.nuoda.common.util.ReflectionsUtil;
import com.slofzx.nuoda.custom.template.enums.SumTypeEnum;
import com.slofzx.nuoda.evaluation.feign.ComputeInvokeClient;
import com.slofzx.nuoda.evaluation.project.entity.BatchInfo;
import com.slofzx.nuoda.evaluation.project.entity.ProjectYearData;
import com.slofzx.nuoda.evaluation.project.util.BusiUtil;
import com.slofzx.nuoda.evaluation.project.vo.*;
import com.slofzx.nuoda.evaluation.steretype.ExcelExportConfig;
import com.slofzx.nuoda.evaluation.steretype.ExcelExportItem;
import com.slofzx.nuoda.excel.builder.AbstractExcelBuilder;
import com.slofzx.nuoda.excel.entity.CellConfig;
import com.slofzx.nuoda.excel.entity.SheetConfig;
import com.slofzx.nuoda.excel.entity.TemplateConfig;
import com.slofzx.nuoda.excel.vo.ExcelPreviewDataVO;
import com.slofzx.nuoda.expression.ExpressionInvoker;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;

import org.springframework.util.StopWatch;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 合并导出excel数据构建器
 *
 * @author sunfuyong
 */
public class MergeExportExcelBuilder extends AbstractExcelExtendBuilder {

    private List<ExportTemplateDetailVO> exportTemplateDetailList;

    private List<ProjectInfoVO> projectInfoList;

    private Map<String, Map<Integer, ProjectReportDetailYearVO>> projectReportDetailYearVOMap;

    private ComputeInvokeClient computeInvokeClient;

    private Map<String,Map<Integer,ProjectYearDataVO>> projectYearDataMap = new HashMap<>();
    private Map<Integer,BatchCommonDataVO> batchCommonDataMap = new HashMap<>();

    protected Map<String, List<ExcelExportItem>> excelExportItemGroupMap = new HashMap<>();

    @Override
    public AbstractExcelExtendBuilder yearList(List<Integer> yearList) {
        return super.yearList(yearList);
    }

   // private Map<String, List<ExcelExportItem>> excelExportItemGroupMap = new HashMap<>();

    public MergeExportExcelBuilder(TemplateConfig config, List<ExcelExportItem> excelExportItemList) {
        super(config);
        for (ExcelExportItem item : excelExportItemList) {
            List<ExcelExportItem> subList = excelExportItemGroupMap.get(item.getGroup());
            if (subList == null) {
                subList = new ArrayList<>();
                excelExportItemGroupMap.put(item.getGroup(), subList);
            }
            subList.add(item);
        }
    }



    public MergeExportExcelBuilder computeInvokeClient(ComputeInvokeClient computeInvokeClient) {
        this.computeInvokeClient = computeInvokeClient;
        return this;
    }
    public MergeExportExcelBuilder exportTemplateDetailList(List<ExportTemplateDetailVO> exportTemplateDetailList) {
        this.exportTemplateDetailList = exportTemplateDetailList;
        return this;
    }
    public MergeExportExcelBuilder batchCommonDataVOMap(List<BatchCommonDataVO> batchCommonDataList) {
        final Map<Integer, BatchCommonDataVO> map = batchCommonDataList.stream().filter(f -> Objects.nonNull(f.getYear())).collect(Collectors.toMap(BatchCommonDataVO::getYear, Function.identity(), (v1, v2) -> v1));
        this.batchCommonDataMap = map;
        return this;
    }

    public MergeExportExcelBuilder projectList(List<ProjectInfoVO> projectInfoList) {
        this.projectInfoList = projectInfoList;
        return this;
    }

    public MergeExportExcelBuilder projectReportDetailYearVOMap(Map<String, List<ProjectReportDetailYearVO>> projectReportDetailYearVOMap) {
        Map<String, Map<Integer, ProjectReportDetailYearVO>> projectReportDetailYearMap = new HashMap<>();
        // 组装年份map
        if (MapUtils.isNotEmpty(projectReportDetailYearVOMap)) {
            for (Map.Entry<String, List<ProjectReportDetailYearVO>> stringListEntry : projectReportDetailYearVOMap.entrySet()) {
                final List<ProjectReportDetailYearVO> value = stringListEntry.getValue();
                if (CollectionUtils.isNotEmpty(value)) {
                    final Map<Integer, ProjectReportDetailYearVO> detailYearVOMap = value.stream()
                            .filter(f -> Objects.nonNull(f) && Objects.nonNull(f.getYear()))
                            .collect(Collectors.toMap(ProjectReportDetailYearVO::getYear, Function.identity(),(v1,v2)->v1));
                    projectReportDetailYearMap.put(stringListEntry.getKey(), detailYearVOMap);
                }
            }
        }
        this.projectReportDetailYearVOMap = projectReportDetailYearMap;
        return this;
    }

    public MergeExportExcelBuilder projectYearDataMap(Map<String,List<ProjectYearDataVO>> projectYearDataMap) {
        for (String key : projectYearDataMap.keySet()) {
            final List<ProjectYearDataVO> projectYearDataVOS = projectYearDataMap.get(key);
            final Map<Integer, ProjectYearDataVO> yearDataVOMap = projectYearDataVOS.stream().collect(Collectors.toMap(ProjectYearDataVO::getYear, Function.identity(), (v1, v2) -> v1));
            this.projectYearDataMap.put(key,yearDataVOMap);
        }
        return this;
    }


    @Override
    public List getDataList(SheetConfig sheetConfig) {
        List<Map<String, Object>> dataList = new ArrayList<>();
       // final StopWatch stopWatch = new StopWatch();
        //ProductTypeEnum productType = BusiUtil.getEnumById(batchInfo.getProductType(), ProductTypeEnum.class);
        for (int i = 0; i < exportTemplateDetailList.size(); i++) {

            final int index = i + 1;

            final ExportTemplateDetailVO detail = exportTemplateDetailList.get(i);
         //   stopWatch.start(detail.getName());

            final HashMap<String, Object> dataMap = new HashMap<String, Object>() {{
                put("order", index);
                put("customType",detail.getCustomType());
//                put(ProjectReportItemEnum.IRR_AFTER_TAX.getId(), irrResult);
            }};
            dataList.add(dataMap);
           // List<CommonExportDataVO> commonExportDataVOList = new ArrayList<>();
            // 过滤掉不符合条件的项目
            final List<ProjectInfoVO> infoVOList = projectInfoList.stream().filter(f -> {
                final String areaMark = detail.getAreaMark();
                if (StringUtils.isNotEmpty(areaMark) && !f.getAreaMark().equals(areaMark)) {
                    return false;
                }
                final String capacityType = detail.getCapacityType();
                if (StringUtils.isNotEmpty(capacityType) && !f.getCapacityType().equals(capacityType)) {
                    return false;
                }
                final String displacementMethod = detail.getDisplacementMethod();
                if (StringUtils.isNotEmpty(displacementMethod) && !f.getDisplacementMethod().equals(displacementMethod)) {
                    return false;
                }
                final String passed = detail.getPassed();
                if (StringUtils.isNotEmpty(passed) && !f.getPassed().equals(passed)) {
                    return false;
                }
                final String poolType = detail.getPoolType();
                if (StringUtils.isNotEmpty(poolType) && !f.getPoolType().equals(poolType)) {
                    return false;
                }
                final String region = detail.getRegion();
                if (StringUtils.isNotEmpty(region) && !f.getRegion().equals(region)) {
                    return false;
                }
                return true;
            }).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(infoVOList)) {
                dataMap.put("project_name",detail.getName());

              //  stopWatch.stop();
                continue;
            }
            // 组装公共计算对象
//            for (ProjectInfoVO vo : infoVOList) {
//                final CommonExportDataVO dataVO = new CommonExportDataVO();
//                dataVO.setProjectInfoVO(vo);
//                dataVO.setProjectReportDetailYearVOMap(projectReportDetailYearVOMap.get(vo.getId()));
//                commonExportDataVOList.add(dataVO);
//
//            }
            ProjectInfoVO typeRow = mergeList2One(infoVOList,ProjectInfoVO.class);
            typeRow.setName(detail.getName());
            typeRow.setCount(infoVOList.size());

            Map<String, Object> partData = BusiUtil.parseObject2Map(typeRow,excelExportItemGroupMap);



            if (partData != null) {
                dataMap.putAll(partData);
            }


            //记录每年数据
            Map<Integer,List<ProjectReportDetailYearVO>> totalDetailYearVOMap = new HashMap<>();
            Map<Integer,List<ProjectYearDataVO>> totalYearDataVOMap = new HashMap<>();
            Map<Integer,List<BatchCommonDataVO>> totalBatchCommonVOMap = new HashMap<>();
            for (ProjectInfoVO vo : infoVOList) {
                Map<Integer,ProjectReportDetailYearVO> yearVOMap = projectReportDetailYearVOMap.get(vo.getId());
                final Map<Integer, ProjectYearDataVO> yearDataVOMap = projectYearDataMap.get(vo.getId());
                for(int year:yearList) {
                    int targetYear = year+vo.getYear()-1;
                    List<ProjectReportDetailYearVO> subList = totalDetailYearVOMap.get(year);
                    List<ProjectYearDataVO> subDataList = totalYearDataVOMap.get(year);
                     List<BatchCommonDataVO> sDataList = totalBatchCommonVOMap.get(year);
                    if(subList == null) {
                        subList = new ArrayList<>();
                        totalDetailYearVOMap.put(year,subList);
                    }
                    if (subDataList == null) {
                        subDataList = new ArrayList<>();
                        totalYearDataVOMap.put(year,subDataList);
                    }
                    if (sDataList == null) {
                        sDataList = new ArrayList<>();
                        totalBatchCommonVOMap.put(year,sDataList);
                    }
                    if(MapUtils.isNotEmpty(yearVOMap)) {
                        ProjectReportDetailYearVO yearData = yearVOMap.get(targetYear);
                        subList.add(yearData);
                    }
                    if (MapUtils.isNotEmpty(yearDataVOMap)) {
                        final ProjectYearDataVO projectYearDataVO = yearDataVOMap.get(targetYear);
                        subDataList.add(projectYearDataVO);
                    }
                    if (MapUtils.isNotEmpty(batchCommonDataMap)) {
                        final BatchCommonDataVO batchCommonDataVO = batchCommonDataMap.get(targetYear);
                        if (batchCommonDataVO!=null) {
                            sDataList.add(batchCommonDataVO);
                        }
                    }

                }
            }
            List<ProjectReportDetailYearVO> groupYearList = new ArrayList<>();
            List<ProjectYearDataVO> groupYearDataList = new ArrayList<>();
            List<BatchCommonDataVO> groupBatchDataList = new ArrayList<>();
            for(int year:yearList) {
                ProjectReportDetailYearVO yearData = mergeList2One(totalDetailYearVOMap.get(year),ProjectReportDetailYearVO.class);
                groupYearList.add(yearData);
                final ProjectYearDataVO projectYearDataVO = mergeList2One(totalYearDataVOMap.get(year), ProjectYearDataVO.class);
                groupYearDataList.add(projectYearDataVO);
                final List<BatchCommonDataVO> commonDataVOS = totalBatchCommonVOMap.get(year);
                if (CollectionUtils.isNotEmpty(commonDataVOS)) {
                    final BatchCommonDataVO batchCommonDataVO = mergeList2One(commonDataVOS, BatchCommonDataVO.class);
                    groupBatchDataList.add(batchCommonDataVO);
                }
            }
            Map<String,Object> yearDataMap = BusiUtil.parseYearDataList2Map(groupYearList,excelExportItemGroupMap,ProjectReportDetailYearVO.class);
            Map<String,Object> yearParamDataMap = BusiUtil.parseYearDataList2Map(groupYearDataList,excelExportItemGroupMap,ProjectYearDataVO.class);
            Map<String,Object> batchParamDataMap = BusiUtil.parseYearDataList2Map(groupBatchDataList,excelExportItemGroupMap,ProjectYearDataVO.class);
            if(yearDataMap!=null) {
                dataMap.putAll(yearDataMap);
            }
            if (yearParamDataMap!= null) {
                dataMap.putAll(yearParamDataMap);
            }
            if (batchParamDataMap != null) {
                dataMap.putAll(batchParamDataMap);
            }
//            final List<ComputeData> computeDataList = projectIdList.stream().filter(StringUtils::isNotEmpty).map(m -> computeDataMap.get(m)).filter(Objects::nonNull).collect(Collectors.toList());

            //处理公式计算
            computeExpression(sheetConfig, dataMap);

           // stopWatch.stop();

        }
       // System.out.println(stopWatch.prettyPrint());
        // 计算税后内部收益率和投资回收期
        Map<Object,Map> dataListMap = new HashMap<>();
        Map<String,List<Double>> cashFlowParamMap = new HashMap<>();
        Map<String,List<Double>> sumCashFlowParamMap = new HashMap<>();
        for (Map<String, Object> map : dataList) {
            final Object name = map.get("customType");
            dataListMap.put(name,map);
            List<Double> cashFlowList = new ArrayList<>();
            Map<Integer,Double> cashFlowMap = (Map<Integer,Double>)map.get("cash_flow_after_tax#map");
            if (MapUtils.isNotEmpty(cashFlowMap)) {
                final ArrayList<Integer> yearList = new ArrayList<>(cashFlowMap.keySet());
                Collections.sort(yearList);
                for (Integer year : yearList) {
                    final Double aDouble = cashFlowMap.get(year);
                    cashFlowList.add(aDouble == null ? 0D: aDouble);
                }
                cashFlowParamMap.put((String) name,cashFlowList);
            }

            Map<Integer,Double> sumCashFlowMap = (Map<Integer,Double>)map.get("sum_cash_flow_after_tax#map");
            if (MapUtils.isNotEmpty(sumCashFlowMap)) {
                List<Double> sumCashFlowList = new ArrayList<>();
                for (Integer year : yearList) {
                    final Double value = sumCashFlowMap.get(year);
                    sumCashFlowList.add(value == null ? 0D : value);
                }
                sumCashFlowParamMap.put((String) name, sumCashFlowList);
            }

        }
        logger.info("cashFlowParamMap：{}",cashFlowParamMap);
        logger.info("sumCashFlowParamMap：{}",sumCashFlowParamMap);
        final Map<String, Double> irrResult = computeInvokeClient.irrResult(cashFlowParamMap).getData();
        final Map<String, Double> pbpResult = computeInvokeClient.pbpResult(sumCashFlowParamMap).getData();
        for (Object name : dataListMap.keySet()) {
            Map dataMap = dataListMap.get(name);
            if (MapUtils.isEmpty(dataMap)) {
                continue;
            }
            if (MapUtils.isNotEmpty(irrResult)) {
                dataMap.put("irr_after_tax",irrResult.get(name)==null?"":irrResult.get(name)*100);
            }
            //大庆不考虑已发生年份，投资回收期需要加1
            if(MapUtils.isNotEmpty(pbpResult)) {
                dataMap.put("pbp_after_tax", pbpResult.get(name) == null ? "" : pbpResult.get(name) + 1);
            }
        }
        final ArrayList<Object> list = new ArrayList<>(exportTemplateDetailList.size());
        for (ExportTemplateDetailVO exportTemplateDetailVO : exportTemplateDetailList) {
            list.add(dataListMap.get(exportTemplateDetailVO.getCustomType()));
        }
        return list;
    }

    /**
     * 将数据转换为map
     *
     * @return
     */
    protected <T> T mergeList2One(List<T> dataList,Class<T> clz) {
        T result = null;
        try {
            result = clz.newInstance();
        } catch (Exception e) {
            logger.error("创建类 {} 实例失败",clz.getName(),e);
        }
        if (clz == null || dataList == null||result == null) {
            return result;
        }
        List<Field> fieldList = ReflectionsUtil.getAllAccessibleFields(clz);
        Set<Class> supportDataTypeSet = new HashSet<Class>() {{
            add(Double.class);
            add(double.class);
            add(Integer.class);
            add(int.class);
        }};
        for (Field field : fieldList) {
            if(Modifier.isFinal(field.getModifiers())||Modifier.isStatic(field.getModifiers())){
                //如果是final或static字段，忽略
                continue;
            }
            Class dataTypeClass = field.getType();
            if (supportDataTypeSet.contains(dataTypeClass) == false) {
                continue;
            }
            try {
                field.setAccessible(true);
                Object sumValue = field.get(result);
                for (T dataItem : dataList) {
                    if(dataItem == null) {
                        continue;
                    }
                    if (Double.class.equals(dataTypeClass)) {
                        Double value = DataConvertUtil.parse2Double(field.get(dataItem), null);
                        if (sumValue == null) {
                            sumValue = value;
                        } else if (value != null) {
                            sumValue = (Double) sumValue + value;
                        }
                    } else if (double.class.equals(dataTypeClass)) {
                        Double value = DataConvertUtil.parse2Double(field.get(dataItem));
                        if (sumValue == null) {
                            sumValue = value;
                        } else {
                            sumValue = (double) sumValue + value;
                        }
                    } else if (Integer.class.equals(dataTypeClass)) {
                        Integer value = DataConvertUtil.parse2Int(field.get(dataItem), null);
                        if (sumValue == null) {
                            sumValue = value;
                        } else if (value != null) {
                            sumValue = (Integer) sumValue + value;
                        }
                    } else if (int.class.equals(dataTypeClass)) {
                        Integer value = DataConvertUtil.parse2Int(field.get(dataItem));
                        if (sumValue == null) {
                            sumValue = value;
                        } else {
                            sumValue = (Integer) sumValue + value;
                        }
                    }
                }
                field.set(result, sumValue);

            } catch (IllegalAccessException e) {
                logger.error("执行mergeList2One 字段值值合并失败-{}::{}",clz.getName(),field.getName(),e);
            }
        }
        return result;
    }
}
